from nacos import NacosClient

from config.nacos_config import NacosConfig
from core.config import Config
from core.singleton_meta import SingletonMeta
import yaml


class NacosV1(metaclass=SingletonMeta):
    """
    Nacos客户端封装类(v1版本SDK)

    主要功能:
    1. 服务注册: 将服务实例注册到Nacos服务端
    2. 配置获取: 从Nacos获取配置信息
    3. 配置监听: 监听配置变更并自动更新本地配置

    使用单例模式确保全局只有一个Nacos客户端实例
    """

    def __init__(self):
        """
        初始化Nacos客户端

        1. 获取Nacos配置
        2. 如果启用Nacos则创建客户端连接
        3. 注册服务到Nacos
        4. 启动配置变更监听
        """
        # 获取Nacos相关配置
        self.config: NacosConfig = Config.get(NacosConfig)
        # 如果未启用Nacos则直接返回
        if not self.config.enable:
            return
        # 创建Nacos客户端，连接到指定服务器和命名空间
        self.client: NacosClient = NacosClient(self.config.get_server_address(), namespace=self.config.namespace)
        # 注册服务实例
        self.register_service()
        # 启动配置监听
        self.listen_config()

    def register_service(self):
        """
        向Nacos注册服务实例

        遍历服务实例列表，将每个实例注册到Nacos服务中心
        设置实例为临时实例(ephemeral=True)，确保服务异常时能自动从注册表移除
        设置心跳间隔为3秒，确保服务健康状态能及时更新
        """
        for service in self.config.get_service_data():
            self.client.add_naming_instance(
                service_name=service.name,  # 服务名称
                ip=service.ip,  # 服务IP地址
                port=service.port,  # 服务端口
                group_name=self.config.group,  # 服务所属分组
                healthy=True,  # 初始状态为健康
                weight=1.0,  # 服务权重
                ephemeral=True,  # 临时实例，服务停止后会自动注销
                heartbeat_interval=3,  # 心跳间隔，单位秒
            )

    def unregister_service(self):
        """
        从Nacos注销服务实例

        在服务关闭前调用，主动从Nacos服务中心移除服务实例
        避免服务已停止但在Nacos中仍显示为可用的情况
        """
        if not self.config.enable:
            return
        for service in self.config.get_service_data():
            self.client.remove_naming_instance(service.name, service.ip, service.port)

    def listen_config(self):
        """
        监听Nacos配置变更

        添加配置监听器，当配置发生变化时自动回调_config_listener函数
        实现配置热更新，无需重启服务即可应用新配置
        """
        if not self.config.enable and not self.config.enable_listen:
            return
        self.client.add_config_watcher(
            self.config.get_config_data().data_id,  # 配置ID
            self.config.get_config_data().group,  # 配置组
            _config_listener,  # 配置变更回调函数
        )

    def get_config(self, data_id: str, group: str) -> dict:
        """
        从Nacos获取配置并解析为字典

        Args:
            data_id: 配置ID，标识具体的配置文件
            group: 配置组，配置的分组

        Returns:
            dict: 解析后的配置字典，如果未启用Nacos或获取失败则返回空字典
        """
        if not self.config.enable:
            return {}
        # 获取配置内容(YAML格式)并解析为字典
        return yaml.safe_load(self.client.get_config(data_id, group) or '')


async def _config_listener(tenant: str, data_id: str, group: str, content: str):
    """
    Nacos配置变更监听回调函数

    当监听的配置发生变更时，此函数会被自动调用
    解析新的配置内容并更新全局配置对象

    Args:
        tenant: 租户/命名空间
        data_id: 配置ID
        group: 配置组
        content: 变更后的配置内容(YAML格式字符串)
    """
    # 解析YAML格式的配置内容为字典
    content_dict = yaml.safe_load(content)
    # 更新全局配置对象
    Config().update_config(content_dict)
